package de.luh.slimpp

import de.luh.slimpp.slimPP.ClassDefinition
import de.luh.slimpp.slimPP.Model
import java.util.HashMap
import java.util.HashSet
import java.util.LinkedList

class InternalTypeDatabase {

	var names = new HashSet<String>
	var nameToClassMap = new HashMap<String, ClassDefinition>

	/**
	 * @param namespacesResolved all the class definitions in the model need to have their fully
	 * qualified names with all namespaces resolved
	 */
	new(Model namespacesResolved) {
		for (cls : namespacesResolved.eAllContents.toIterable.filter(typeof(ClassDefinition))) {
			val name = cls.qualifiedName.namespaces.join('', '.', '.', [it]) + cls.qualifiedName.name
			names.add(name)
			nameToClassMap.put(name, cls)
		}
	}

	def findHeader(String type) {
		val cls = findClass(type)
		if (cls != null) {
//			cls.headerFilename
		}
		null
	}

	def findHeader(String type, ClassDefinition currentClass) {
		val cls = findClass(type, currentClass)
		if (cls != null) {

			// TODO remove the prefixing namespaces from the header
//			cls.headerFilename
		}
		null
	}

	def findClass(String type) {
		return nameToClassMap.get(type)
	}

	/**
	 * Looks through all known classes from the model given in the constructor and tries to find the given type.
	 * The current class is needed because its namespace is relevant for searching for the type since it is the
	 * starting point form which a relative search is done.
	 * 
	 * @param type a fully qualified type name, e.g. my.namespace.String
	 * @param currentClass the class from which the search is started, the class' scope is important
	 * 
	 * @return the ClassDefinition for the type or null if not
	 */
	def findClass(String type, ClassDefinition currentClass) {

		// recursively go through all the scopes (going up until finding the global scope) and look for the type
		val scope = new LinkedList<String>(currentClass.qualifiedName.namespaces)
		for (i : 0 .. scope.size) {

			// what would the type look like if it was in the current scope? like this:
			val searchFor = scope.join('', '.', '.', [it]) + type

			// see if we know that type
			if (names.contains(searchFor)) {
				return nameToClassMap.get(searchFor)
			}

			// look one namespace up in the next iteration
			if (!scope.empty) {
				scope.removeLast
			}
		}

		// no fitting type was found
		return null
	}
}
